import {native, sys} from 'cc';

/**
 * 存储管理器
 */
export class StorageManager {
    /**
     * 文件的存储路径
     */
    private path: string;
    /**
     * 缓存
     */
    private caches: Map<string, string> = new Map<string, string>();

    /**
     * 存储管理器实例
     */
    private static INSTANCE: StorageManager;

    /**
     * 获取存储管理器实例
     */
    public static getInstance(): StorageManager {
        if (!this.INSTANCE) {
            this.INSTANCE = new StorageManager();
        }
        return this.INSTANCE;
    }

    private constructor() {
        // 初始化
        this.init();
    }

    /**
     * 初始化
     */
    private init() {
        // 初始化文件的存储路径
        this.initPath();
        // 初始化缓存
        this.initCaches();
    }

    /**
     * 初始化路径
     */
    private initPath() {
        // 根据系统或平台寻找配置路径
        switch (sys.os) {
            case sys.OS.WINDOWS:
                this.path = "src/conf";
                break;
            case sys.OS.LINUX:
                this.path = "./conf";
                break;
            case sys.OS.OSX:
                this.path = "./conf";
                break;
            default:
                // 原生平台
                if (sys.isNative) {
                    this.path = native.fileUtils.getWritablePath();
                    this.path = `${this.path}/conf}`;
                } else {
                    this.path = "src/conf";
                }
                break;
        }
    }

    /**
     * 初始化缓存
     */
    private initCaches() {
        // 本地
        const json = this.getJsonFromLocal();
        if (json) {
            let jsonMap: { [key: string]: string } = JSON.parse(json);
            for (let k in jsonMap) {
                this.caches.set(k, jsonMap[k]);
            }
        }
    }

    /**
     * 持久化数据
     */
    private saveDataToLocal() {
        // Map转索引签名，原因是JSON.stringify(Map)得到的结果为{}
        let jsonMap: { [key: string]: string } = {};
        this.caches.forEach((v, k) => jsonMap[k] = v);

        // 本地
        // 如果是原生平台
        if (sys.isNative) {
            // 那么就使用原生平台存储机制
            native.fileUtils.writeStringToFile(JSON.stringify(jsonMap), this.path);
        } else {
            // 否则就使用localStorage存储
            sys.localStorage.setItem(this.path, JSON.stringify(jsonMap));
        }
    }

    /**
     * 设置数据
     * 类型：
     * 1.引用类型的值用JSON
     * 2.基础类型的值直接存
     *
     * @param key 键
     * @param value 值
     */
    public setData(key: string, value: string) {
        // 内存
        this.caches.set(key, value);

        // 本地
        this.saveDataToLocal();
    }

    /**
     * 删除指定Key的数据
     *
     * @param key 键
     */
    public deleteData(key: string) {
        // 内存
        this.caches.delete(key);

        // 本地
        this.saveDataToLocal();
    }

    /**
     * 清空所有数据
     */
    public clear() {
        // 内存
        this.caches.clear();

        // 本地
        // 如果是原生平台
        if (sys.isNative) {
            // 那么就使用原生平台存储机制
            native.fileUtils.removeFile(this.path);
        } else {
            // 否则就使用localStorage存储
            sys.localStorage.removeItem(this.path);
        }
    }

    /**
     * 获取数据
     *
     * @param key 键
     */
    public getData(key: string): string {
        // 内存
        if (this.caches.has(key)) {
            return this.caches.get(key);
        }

        // 本地
        return this.getDataFromLocal(key);
    }

    /**
     * 从本地获取数据
     *
     * @param key 键
     */
    private getDataFromLocal(key: string): string {
        // 获取json字符串
        let json = this.getJsonFromLocal();
        // 当json不存在时
        if (!json) {
            return "";
        }

        // json转map
        let jsonMap: { [key: string]: string } = JSON.parse(json);
        for (let k in jsonMap) {
            // 找到key
            if (k === key) {
                // 获取值
                let value = jsonMap[k];
                // 刷新缓存
                this.caches.set(key, value);
                // 返回结果
                return value;
            }
        }

        // 当key不存在时，返回空字符串
        return "";
    }

    /**
     * 从本地获取JSON
     */
    private getJsonFromLocal(): string {
        if (sys.isNative) {
            return native.fileUtils.getStringFromFile(this.path);
        } else {
            return sys.localStorage.getItem(this.path);
        }
    }
}